package com.apobates.jforum.grief.schema2doc.core.strategy;

import com.apobates.jforum.grief.schema2doc.core.SchemaTableStrategy;
import com.apobates.jforum.grief.schema2doc.core.schema.SchemaDialect;
import java.util.Optional;
import java.util.function.Predicate;
/**
 * 基于表名正则匹配
 * 示例: 匹配特定的前缀:
 *  MySQL '^(audit|think)_'  以audit_和think_开头的
 *  Oracle '^(ADL|ARTICLE)_' 以ADL_和ARTICLE_开头的
 *  SQLServer 'JB_FR_%'      以JB_FR_开头的
 */
public class SchemaTableRegMatchStrategy implements SchemaTableStrategy {
    private final String expression;
    // 匹配的附加参数
    private final String mode;
    /**
     * 初始化
     * MySQL:      REGEXP/POSIX regular expression
     * MariaDB:    REGEXP/POSIX regular expression
     * PostgreSQL: regexp_match/POSIX regular expression(flags)
     * Oracle:     REGEXP_LIKE/POSIX regular expression(match_parameter)
     * SQLServer:  PATINDEX/原生不支持不支持RegExp.
     * SQLite:     不支持正则表达/不适用此策略
     * Informix:   regex_match/POSIX regular expression(copts)
     * @param expression regular expression 要求带有表达式原生单引号
     * @param mode 匹配模式, 适用于:
     *                      Oracle https://docs.oracle.com/cd/B13789_01/server.101/b10759/conditions018.htm#SQLRF00501
     *                      PostgreSQL https://www.postgresql.org/docs/10/functions-matching.html#POSIX-EMBEDDED-OPTIONS-TABLE
     *                      Informix https://www.ibm.com/docs/en/informix-servers/12.10?topic=routines-regex-match-function
     */
    public SchemaTableRegMatchStrategy(String expression, String mode) {
        this.expression = expression;
        this.mode = mode;
    }
    /**
     * 初始化
     * MySQL:      REGEXP/POSIX regular expression
     * MariaDB:    REGEXP/POSIX regular expression
     * PostgreSQL: regexp_match/POSIX regular expression(flags=i)
     * Oracle:     REGEXP_LIKE/POSIX regular expression(match_parameter=i)
     * SQLServer:  PATINDEX/原生不支持不支持RegExp.
     * SQLite:     不支持正则表达/不适用此策略
     * Informix:   regex_match/POSIX regular expression(copts=2)
     * @param expression regular expression 要求带有表达式原生单引号
     */
    public SchemaTableRegMatchStrategy(String expression) {
        this(expression, "i");
    }

    @Override
    public Optional<String> sql(SchemaDialect dialect) {
        if(dialect == SchemaDialect.MySQL || dialect == SchemaDialect.MariaDB){
            // https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_regexp
            // https://www.oreilly.com/library/view/mysql-cookbook/0596001452/ch04s08.html
            // expr REGEXP pat | expr REGEXP pat
            // 示例: TABLE_NAME REGEXP '^(audit|think)_'
            return Optional.of(String.format("%s REGEXP %s", placeholder, expression));
        }
        if(dialect == SchemaDialect.PostgreSQL){
            // https://www.postgresql.org/docs/10/functions-string.html
            // regexp_match() 函数返回一个字符串数组，它是一个字符串中使用指定的正则表达式的第一次匹配结果。如果字符串中没有包含和正则匹配的内容，则此函数返回 NULL。
            // regexp_match(string text, pattern text [, flags text])
            // 示例:
            return Optional.of(String.format("(REGEXP_MATCH(%s, %s, '%s') IS NOT NULL)", placeholder, expression, mode));
        }
        if(dialect == SchemaDialect.SQLServer){
            // https://learn.microsoft.com/en-us/sql/t-sql/functions/patindex-transact-sql?view=sql-server-ver16
            // PATINDEX ( '%pattern%' , expression )
            // 示例: PATINDEX('JB_FR_%', TABLE_NAME) >0;
            return Optional.of(String.format("PATINDEX(%s, %s)>0", expression, placeholder));
        }
        if(dialect == SchemaDialect.Oracle){
            // https://docs.oracle.com/cd/B13789_01/server.101/b10759/conditions018.htm
            // REGEXP_LIKE(source_string, search_pattern [, match_parameter]);
            // 示例: REGEXP_LIKE(TABLE_NAME, '^(ADL|ARTICLE)_', 'i')
            return Optional.of(String.format("REGEXP_LIKE(%s, %s, '%s')", placeholder, expression, mode));
        }
        if (dialect == SchemaDialect.Informix){
            // https://www.ibm.com/docs/en/informix-servers/12.10?topic=routines-regex-match-function
            // and regex_match(tabname, '^(qblob|qjob)_')
            String copts = mode.equals("i")?"2":mode;
            return Optional.of(String.format("REGEX_MATCH(%s, %s, '%s')", placeholder, expression, copts));
        }
        return Optional.empty();
    }

    @Override
    public Predicate<String> filter() {
        return passFilter();
    }
}
